package bll

import (
	"context"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/lib/pq"
	"github.com/xuri/excelize/v2"
	"go-micro.dev/v4/client"
	"golang.org/x/sync/errgroup"
	"gorm.io/gorm"
	"manager/auth"
	"manager/client/grpc"
	log "manager/collector/logger"
	"manager/config"
	"manager/errors"
	"manager/event"
	"manager/lib/trace_log"
	"manager/model"
	"manager/model/entity"
	SignalPo "manager/model/signal"
	"manager/store"
	"manager/store/postgres"
	"manager/store/redis"
	"manager/utils"
	"manager/utils/goroutine_pool"
	"proto/dto"
	"sort"
	"strconv"
	"strings"
	"time"
)

type ebike struct {
	iEbike           store.IEbike
	iUserEbike       store.IUserEbike
	iEbikeType       store.IEbikeType
	iControl         store.IControl
	iStore           store.IStore
	iUserBikeSetting store.IUserBikeSetting
	iAuthTransfer    store.ITransferRecode
}

var Ebike = &ebike{}

func (a *ebike) init() func() {
	a.iEbike = postgres.Ebike
	a.iUserEbike = postgres.UserEbike
	a.iEbikeType = postgres.EbikeType
	a.iControl = postgres.Control
	a.iStore = postgres.Store
	a.iUserBikeSetting = postgres.UserBikeSetting
	a.iAuthTransfer = postgres.TransferRecode
	return func() {}
}

func (a *ebike) onEvent(data *event.Data) {
}

func (a *ebike) Create(ctx context.Context, in *model.EbikeCreateRequest) error {
	var (
		err     error
		ebikeID int64
	)

	// 查询总数, 限制100辆 （这里限制的目的是？ 先放开到10000 add by Albert 2023-09-15）
	rsp, err := a.iEbike.Count(ctx)
	if rsp != nil && rsp.Total > 10000 {
		fmt.Println("ebike create bike total count reach 10000")
		return nil
	}

	// 判断车子是否已经录入
	if bikeId, _ := CacheBike.GetBikeIdBySn(in.SNCode); bikeId > 0 {
		return fmt.Errorf("车辆已存在")
	}

	// 判断车型是否存在
	bikeTypeInfo, err := EbikeType.BikeTypeInfo(in.TypeID)
	if err != nil {
		return errors.EbikeModelNotExist.Error()
	}

	// 车辆名称
	if in.Name == "" {
		in.Name = fmt.Sprintf("%v_%v", bikeTypeInfo.Name, string([]byte(in.SNCode)[len(in.SNCode)-4:]))
	}

	// 车辆图片
	if in.Photo == "" {
		in.Photo = bikeTypeInfo.Image
	}

	// 构建车辆信息
	c := buildEbike(in)
	if in.BindUsers == nil { //为空，初始化
		c.BindUsers = make([]string, 0)
	}

	// 电池类型校验
	if !BatteryType.IsExistBatteryType(in.BatteryType) {
		return errors.BatteryTypeNotExist.Error()
	}

	// 创建车辆
	err = a.iEbike.ExecTx(ctx, func(ct context.Context) error {
		// 创建中控
		if c.ControlId, err = Control.Create(ct, &model.ControlCreateRequest{
			SnCode: in.SNCode,
		}); err != nil {
			log.Error(err)
			return err
		}

		// 创建电池
		if c.BatteryId, err = Battery.Create(ct, &model.BatteryCreateRequest{
			BatteryType: in.BatteryType,
		}); err != nil {
			log.Error(err)
			return err
		}

		//创建车辆
		ebikeID, err = a.iEbike.Create(ct, c)
		if err != nil {
			log.Error(err)
			return errors.Wrap(err, errors.EbikeCreateFailed.Error().Error())
		}

		if ebikeID == 0 {
			log.Errorf("create ebike err  ebikeID %s", c.ID)
			return errors.EbikeCreateFailed.Error()
		}
		return nil
	})

	return err
}

func (a *ebike) createEbikeCallback(ctx context.Context, bike model.DeviceCallBack) error {
	bikeTypeInfo, err := EbikeType.QueryTypeByCode(ctx, bike.Model)
	if err != nil {
		return fmt.Errorf("ControlCode:%s,Model:%s 车辆型号不存在", bike.ControlCode, bike.Model)
	}
	batteryTypeInfo, err := BatteryType.QueryBatteryTypeByCode(ctx, bike.BatteryType)
	if err != nil {
		return fmt.Errorf("ControlCode:%s,BatteryType:%s 电池型号不存在", bike.ControlCode, bike.BatteryType)
	}
	b := &entity.Ebike{
		TypeID:       bikeTypeInfo.ID,
		Name:         bike.Name,
		Photo:        bikeTypeInfo.Image,
		Status:       0,
		FrameCode:    bike.FrameCode,
		EngineCode:   bike.EngineCode,
		Color:        bike.Color,
		BatteryId:    batteryTypeInfo.Id,
		CreatedAt:    time.Now().Unix(),
		UpdatedAt:    time.Now().Unix(),
		SNCode:       bike.ControlCode,
		AESKey:       config.AesKey,
		IV:           config.Iv,
		BindUsers:    make([]string, 0),
		ErpSNCode:    bike.SNCode,
		DeliveryTime: bike.DeliveryTime,
		Factory:      bike.Factory,
	}
	err = a.iEbike.ExecTx(ctx, func(ct context.Context) error {
		var e error
		if b.ControlId, e = Control.Create(ct, &model.ControlCreateRequest{
			SnCode: bike.SNCode,
		}); e != nil {
			return e
		}
		// 创建电池
		if b.BatteryId, e = Battery.Create(ct, &model.BatteryCreateRequest{
			BatteryType: b.BatteryId,
		}); e != nil {
			log.Error(e)
			return e
		}
		ebikeID, e := a.iEbike.Create(ct, b)
		if e != nil {
			log.Error(e)
			return fmt.Errorf("ControlCode：%s 创建记录失败", b.SNCode)
		}
		if ebikeID == 0 {
			log.Errorf("create ebike err  ebikeID %s", b.ID)
			return fmt.Errorf("ControlCode：%s 创建记录失败", b.SNCode)
		}
		return nil
	})
	return err
}

func (a *ebike) updateEbikeCallBack(ctx context.Context, ety entity.Ebike, bike model.DeviceCallBack) error {
	dict := make(map[string]interface{})
	if bike.SNCode != "" {
		dict["erp_sn_code"] = bike.SNCode
	}
	if bike.FrameCode != "" {
		dict["frame_code"] = bike.FrameCode
	}
	if bike.Name != "" {
		dict["name"] = bike.Name
	}
	if bike.Factory != "" {
		dict["factory"] = bike.Factory
	}
	if bike.DeliveryTime != "" {
		dict["delivery_time"] = bike.DeliveryTime
	}
	if bike.EngineCode != "" {
		dict["engine_code"] = bike.EngineCode
	}
	if bike.Color != "" {
		dict["color"] = bike.Color
	}
	dict["updated_at"] = time.Now().Unix()
	if bike.BatteryType != "" {
		batteryTypeInfo, err := BatteryType.QueryBatteryTypeByCode(ctx, bike.BatteryType)
		if err != nil {
			return fmt.Errorf("ControlCode:%s,BatteryType:%s 电池型号不存在", bike.ControlCode, bike.BatteryType)
		}
		batteryInfo, _ := postgres.Battery.Find(ctx, &model.BatteryInfoRequest{
			Id: ety.BatteryId,
		})
		if batteryInfo.BatteryType != batteryTypeInfo.Id {
			postgres.Battery.Update(ctx, batteryInfo.Id, map[string]interface{}{
				"battery_type": batteryTypeInfo.Id,
			})
		}
	}
	if bike.Model != "" {
		bikeTypeInfo, err := EbikeType.QueryTypeByCode(ctx, bike.Model)
		if err != nil {
			return fmt.Errorf("ControlCode:%s,BatteryType:%s 电池型号不存在", bike.ControlCode, bike.BatteryType)
		}
		if bikeTypeInfo.ID != ety.TypeID {
			dict["type_id"] = bikeTypeInfo.ID
		}
	}
	err := a.iEbike.Update(ctx, ety.ID, dict)
	return err
}

// 创建或者更新数据
func (a *ebike) EbikeCallback(ctx context.Context, in *model.DeviceCallBackRequest) (model.DeviceCallBackResponse, error) {
	var resp model.DeviceCallBackResponse
	if len(in.EBikes) > 100 {
		return model.DeviceCallBackResponse{}, errors.EbikeModelTooManyFailed.Error()
	}
	ebikeErrs := make([]model.DeviceCallBackErr, 0, len(in.EBikes))
	for _, bike := range in.EBikes {
		var err error
		errEbike := model.DeviceCallBackErr{
			Sn: bike.SNCode,
		}

		// 获取中控编码
		bike.ControlCode = strings.ToUpper(bike.ControlCode)
		bike.ControlCode = strings.Replace(bike.ControlCode, "KEREN-EBIKE:", "", 1)

		// 中控编码必须为16位
		if len(bike.ControlCode) != 16 {
			errEbike.Msg = "中控编码必须为16位"
			ebikeErrs = append(ebikeErrs, errEbike)
			continue
		}
		if bikeEty, _ := a.iEbike.FindEBikeBySN(ctx, bike.ControlCode); bikeEty.ID == 0 {
			// 更新验证,型号不应该能改变
			err = a.createEbikeCallback(ctx, bike)
		} else {
			err = a.updateEbikeCallBack(ctx, bikeEty, bike)
		}
		if err != nil {
			errEbike.Msg = err.Error()
			ebikeErrs = append(ebikeErrs, errEbike)
		}
	}
	resp.EBikes = ebikeErrs
	return resp, nil
}

func (a *ebike) Update(ctx context.Context, in *model.EbikeUpdateRequest) error {
	var (
		dict = make(map[string]interface{})
	)

	// 查询车辆信息
	ebikeInfo, err := a.iEbike.Find(ctx, in.ID)
	if err != nil {
		return err
	}

	if in.TypeID != nil && ebikeInfo.TypeID != *in.TypeID {
		// 获取车型信息
		bikeTypeInfo, _ := EbikeType.BikeTypeInfo(*in.TypeID)
		if bikeTypeInfo != nil {
			dict["photo"] = bikeTypeInfo.Image
		}
	}

	if in.Name != nil {
		dict["name"] = *in.Name
	}

	if in.Status != nil {
		dict["status"] = *in.Status
	}

	if in.FrameCode != nil {
		dict["frame_code"] = *in.FrameCode
	}

	if in.EngineCode != nil {
		dict["engine_code"] = *in.EngineCode
	}

	if in.Color != nil {
		dict["color"] = *in.Color
	}

	if in.IsBind != nil {
		dict["is_bind"] = *in.IsBind
	}

	if in.Stock != nil {
		dict["stock"] = *in.Stock
	}

	if in.StoreID != nil {
		dict["store_id"] = *in.StoreID
	}

	dict["updated_at"] = time.Now().Unix()

	if in.BindUsers != nil {
		dict["bind_users"] = *in.BindUsers
	}

	if in.DistributeTime != nil {
		dict["distribute_time"] = *in.DistributeTime
	}

	if in.TypeID != nil {
		dict["type_id"] = *in.TypeID
	}

	if in.BatteryType != nil {
		bikeInfo, _ := CacheBike.GetBikeInfoById(in.ID)
		if bikeInfo != nil {
			// 查询电池
			batteryInfo, _ := postgres.Battery.Find(ctx, &model.BatteryInfoRequest{
				Id: bikeInfo.BatteryId,
			})

			if batteryInfo != nil && batteryInfo.BatteryType != *in.BatteryType {
				postgres.Battery.Update(ctx, batteryInfo.Id, map[string]interface{}{
					"battery_type": in.BatteryType,
				})
			}
		}
	}

	// do other update here
	// 更新前删除缓存
	CacheBike.DeleteCache(in.ID)

	// 更新车辆
	err = a.iEbike.Update(ctx, in.ID, dict)
	if err != nil {
		return err
	}

	// 更新后删除缓存
	CacheBike.DeleteCache(in.ID)

	return nil
}

func (a *ebike) Delete(ctx context.Context, in *model.EbikeDeleteRequest) error {
	// 清理缓存
	bikeInfo, _ := CacheBike.GetBikeInfoById(in.ID)
	if bikeInfo != nil {
		CacheBike.DeleteCacheBySn(bikeInfo.SNCode)
	}

	ety, _ := a.iEbike.FindByParameter(ctx, &model.EbikeInfo{
		SNCode: bikeInfo.SNCode,
	})

	// 判断车辆是否绑定
	if ety != nil && ety.IsBind == 1 {
		return errors.EbikeAlreadyBound.Error()
	}

	return a.iEbike.ExecTx(ctx, func(ctx context.Context) error {
		// 删除车辆
		if err := a.iEbike.Delete(ctx, in.ID); err != nil {
			return err
		}

		// 删除中控
		if err := a.iControl.Delete(ctx, bikeInfo.ControlId); err != nil {
			return err
		}

		// 删除电池
		if err := Battery.Delete(ctx, &model.BatteryDeleteRequest{Id: bikeInfo.BatteryId}); err != nil {
			return err
		}

		return nil
	})
}

func (a *ebike) List(ctx context.Context, in *model.EbikeListRequest) (*model.EbikesListResponse, error) {
	var (
		err error
		out = &model.EbikesListResponse{}
	)

	in.Size, in.Index = utils.PageUtil(in.Size, in.Index)

	total, list, err := a.iEbike.WebList(ctx, in)
	if err != nil {
		log.Error(err)
		return nil, errors.EbikeQueryFailed.Error()
	}

	// 查询车辆统计数据
	count, err := a.iEbike.Count(ctx)
	if err != nil {
		log.Error(err)
		return nil, errors.EbikeQueryFailed.Error()
	}

	// 获取设备在线状态
	for i, v := range list {
		status := a.DeviceStatus(ctx, v.ID)
		list[i].Is4gOnline = status.OnlineStatus > 0
	}

	out.BindCount = int(count.BindCount)
	out.DeviceCount = int(count.Total)
	out.Total = int(total)
	out.Data = list

	return out, err
}

func (a *ebike) GetSn(ebikeId int64) (string, error) {
	info, err := a.iEbike.FindByParameter(context.Background(), &model.EbikeInfo{
		ID: ebikeId,
	})

	if err != nil {
		return "", err
	}

	return info.SNCode, nil
}

func (a *ebike) GetBikeIdBySnCode(sn string) (int64, error) {
	info, err := a.iEbike.FindByParameter(context.Background(), &model.EbikeInfo{
		SNCode: sn,
	})

	if err != nil {
		return 0, err
	}

	return info.ID, nil
}

// GetBikeInfoBySnCode 根据sn获取车辆信息
func (a *ebike) GetBikeInfoBySnCode(sn string) (bikeInfo *model.EbikeInfo, err error) {
	info, err := a.iEbike.FindByParameter(context.Background(), &model.EbikeInfo{
		SNCode: sn,
	})

	if err != nil {
		return nil, err
	}

	bikeInfo = model.EbikeEntityToDto(info)
	return bikeInfo, nil
}

// IsLock 是否为锁车状态
func (a *ebike) IsLock(bikeId int64) bool {
	status := a.DeviceStatus(context.Background(), bikeId)
	return status.LockStatus == 1
}

// IsManager 是否为车主
func (a *ebike) IsManager(userId, ebikeId int64) bool {
	info, err := a.iUserEbike.FindByParameter(context.Background(), &model.UserEbikeRequest{
		UserID:  &userId,
		EbikeID: &ebikeId,
	})

	if err != nil {
		return false
	}

	return info.IsManager > 0
}

func buildEbike(in *model.EbikeCreateRequest) *entity.Ebike {
	// todo: check the entity is required
	return &entity.Ebike{

		TypeID: in.TypeID,

		Name: in.Name,

		Photo: in.Photo,

		Status: in.Status,

		FrameCode: in.FrameCode,

		EngineCode: in.EngineCode,

		SNCode: in.SNCode,

		Color: in.Color,

		Stock: in.Stock,

		AESKey: config.AesKey,

		IV: config.Iv,

		BindUsers: in.BindUsers,
	}
}

// Bind 车辆绑定
func (a *ebike) Bind(ctx context.Context, in *model.EbikeAppBindRequest) error {
	defer utils.ExceptionCatch()
	var (
		err    error
		userID int64
	)
	defer func() {
		trace_log.DebugLogger(in.SnCode, "绑定车辆 Bind in:", utils.ToJsonString(in), " err:", err)
	}()

	userID, err = auth.ContextUserID(ctx)
	if err != nil || userID == 0 {
		return errors.InvalidToken.Error()
	}

	// 如果存在先删除绑定关系
	/*	bikeInfo, _ := CacheBike.GetBikeInfoBySn(in.SnCode)
		info, _ := postgres.UserEbike.FindByParameter(ctx, &model.UserEbikeRequest{
			UserID:  &userID,
			EbikeID: &bikeInfo.ID,
		})
		if info != nil && info.ID > 0 && bikeInfo.IsBind == 0 {
			postgres.UserEbike.Delete(ctx, info.ID)
		}*/

	// 绑定车辆
	err = a.iEbike.Bind(ctx, in.SnCode, userID)
	if err != nil {
		return err
	}

	TableLog.AddOperatorLog(userID, EnAdd, "user_bike", fmt.Sprintf("%v_%v", "Bind", utils.ToJsonString(in)))

	go func() {
		utils.ExceptionCatch()
		bikeDto, err := a.iEbike.FindByParameter(ctx, &model.EbikeInfo{
			SNCode: in.SnCode,
		})
		if err != nil {
			log.Error(err)
			return
		}

		// 发送车辆绑定车主事件
		event.Emit(&event.Data{
			Type: event.Event_Bind_Bike,
			Data: &event.BindBike{
				BikeId: bikeDto.ID,
				UserId: userID,
			},
		})
	}()
	return nil
}

// UnBind 车辆解除绑定
func (a *ebike) UnBind(ctx context.Context, in *model.EbikeBaseRequest) error {
	defer utils.ExceptionCatch()
	var (
		err    error
		userID int64
		ety    *entity.Ebike
	)

	defer func() {
		trace_log.DebugLogger(ety.SNCode, "解绑车辆 UnBind in:", utils.ToJsonString(in), " err:", err)
	}()

	//请求用户信息
	userID, err = auth.ContextUserID(ctx)
	if err != nil {
		return errors.InvalidToken.Error()
	}

	b := a.IsManager(userID, in.ID)
	if !b {
		return errors.EbikeNotPermission.Error()
	}

	//查询车辆信息
	ety, err = a.iEbike.Find(ctx, in.ID)
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		return errors.EbikeNotExist.Error()
	}
	if err != nil {
		return err
	}

	//车辆解除绑定
	if ety.IsBind == int(model.BindNo) {
		return errors.EbikeNotBound.Error()
	}

	// 绑定列表
	_, list, _ := a.iUserEbike.List(ctx, &model.UserEbikeListRequest{
		EbikeID: &in.ID,
	})

	// 发出解绑事件
	for i := 0; i < len(list); i++ {
		data := &event.UnBindBike{
			BikeId: list[i].EbikeID,
			UserId: list[i].UserID,
		}

		// 发送车辆解绑车主事件
		event.Emit(&event.Data{
			Type: event.Event_UnBind_Bike,
			Data: data,
		})
	}

	// 解绑
	err = a.iEbike.UnBind(ctx, userID, ety.ID, true)
	if err != nil {
		return err
	}

	// 关闭无感启动
	zero := int32(0)
	data := dto.SwitchRequest{
		Sn:              ety.SNCode,
		SenselessUnlock: &zero,
	}
	// 关闭无感启动
	if _err := SignalV2.SendToggleToDevice(&SignalPo.ToggleReq{
		EbikeId:       ety.ID,
		SwitchRequest: data,
	}); _err != nil {
		// 判断车辆是否在线
		status := a.DeviceStatus(ctx, ety.ID)
		if status.OnlineStatus == 0 {
			DelayCommand.AddCommand(ety.SNCode, SignalToggle, data)
		}
	}

	// 下发清理中控的指令
	goroutine_pool.GetPool().Push(nil, func(data interface{}) error {
		_ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		bytes, _ := hex.DecodeString("fe03aa6802")
		RpcCall(ety.SNCode, func(addr string, err error) error {
			if err != nil {
				return err
			}
			if _, err = grpc.Cmd.BinaryReq(_ctx, &dto.BinaryRequest{
				Sn:  ety.SNCode,
				Hex: bytes,
			}, func(options *client.CallOptions) {
				options.Address = []string{addr}
			}); err != nil {
				trace_log.DebugLogger(ety.SNCode, "解除绑定下发解除中控相关信息命令失败 err:", err)
			}
			return err
		})
		return nil
	})

	// 添加日志
	TableLog.AddOperatorLog(userID, EnDel, "user_bike", fmt.Sprintf("%v_%v_true", "UnBind", utils.ToJsonString(&event.UnBindBike{
		BikeId: ety.ID,
		UserId: userID,
	})))
	return err
}

// DeviceStatus 设备状态
func (a *ebike) DeviceStatus(ctx context.Context, bikeId int64) *model.DeviceStatusRsp {
	// 获取车辆状态
	powerStatus := DeviceStatus.GetPowerStatus(bikeId)

	// 车辆信息
	bikeInfo, _ := CacheBike.GetBikeInfoById(bikeId)
	// 获取设备属性
	statusMap, _ := redis.KV.HGetAll(ctx, fmt.Sprintf("device_status:%v", bikeInfo.SNCode))

	lockStatus := 0
	onlineStatus := 0
	if len(statusMap) > 0 {
		for k, v := range statusMap {
			if k == "lock" && v == "1" {
				lockStatus = 1
			}

			if k == "online" && v == "1" {
				onlineStatus = 1
			}
		}
	}

	return &model.DeviceStatusRsp{
		EbikeId:      bikeId,
		PowerStatus:  powerStatus,
		LockStatus:   lockStatus,
		OnlineStatus: onlineStatus,
	}
}

// AppList 用户车辆列表
func (a *ebike) AppList(ctx context.Context, userId int64) ([]*model.EbikeAppListResponse, error) {
	var (
		err error
		out []*model.EbikeAppListResponse
	)

	// 车辆列表
	out, err = a.iEbike.AppList(ctx, userId)
	if len(out) == 0 {
		return nil, nil
	}

	// 分享的车辆
	var newBikeList []*model.EbikeAppListResponse
	var shareIds []int64
	for i := 0; i < len(out); i++ {
		if out[i].IsManager == 1 {
			newBikeList = append(newBikeList, out[i])
			continue
		}

		shareIds = append(shareIds, out[i].ID)
	}

	// 清理过期车辆
	if len(shareIds) > 0 {
		_, expireIds, _ := ShareEbike.GetEffectiveShareEbike(ctx, userId, shareIds)
		for i := 0; i < len(out); i++ {
			if out[i].IsManager == 1 {
				continue
			}

			if _, ok := expireIds[out[i].ID]; ok {
				goroutine_pool.GetPool().Push(&event.UnBindBike{
					BikeId: out[i].ID,
					UserId: userId,
				}, func(data interface{}) error {
					// 发送车辆解绑车主事件
					event.Emit(&event.Data{
						Type: event.Event_UnBind_Bike,
						Data: data,
					})

					// 添加日志
					TableLog.AddOperatorLog(0, EnDel, "user_bike", fmt.Sprintf("%v_%v", "AppList", utils.ToJsonString(data)))
					return nil
				})
				continue
			}

			newBikeList = append(newBikeList, out[i])
		}
	}

	if len(newBikeList) == 0 {
		return nil, nil
	}

	out = newBikeList
	// 车辆ID
	var bikeIds []int64
	var batteryIds []int64
	for i := 0; i < len(out); i++ {
		batteryIds = append(batteryIds, out[i].BatteryId)
		bikeIds = append(bikeIds, out[i].ID)
	}

	// todo: 查询用户自定义车辆名称和图片
	var g errgroup.Group
	// 用户车辆数据map
	//bikeMap := map[int64]*entity.UserBikeSetting{}
	//// 用户自定义车辆数据(获取最新的一条修改记录)
	//g.Go(func() error {
	//	_, list, _err := a.iUserBikeSetting.List(ctx, &model.UserBikeSettingListRequest{
	//		Index:   1,
	//		Size:    -1,
	//		UserId:  &userId,
	//		BikeIds: bikeIds,
	//	})
	//
	//	if _err != nil {
	//		return nil
	//	}
	//
	//	for i := 0; i < len(list); i++ {
	//		if _, ok := bikeMap[list[i].EbikeId]; ok {
	//			continue
	//		}
	//		bikeMap[list[i].EbikeId] = list[i]
	//	}
	//
	//	return err
	//})

	// 车辆配置信息
	settingsMap := make(map[int64]*entity.Setting)
	g.Go(func() error {
		_, settings, _ := postgres.Setting.BikeList(bikeIds)
		for i := 0; i < len(settings); i++ {
			settingsMap[settings[i].EbikeId] = settings[i]
		}
		return nil
	})

	// 电池信息
	batterMap := make(map[int64]*model.BatteryData)
	g.Go(func() error {
		_, batteryList, _ := postgres.Battery.BatteryInfoList(ctx, batteryIds)
		for i := 0; i < len(batteryList); i++ {
			batterMap[batteryList[i].Id] = batteryList[i]
		}
		return nil
	})

	if err = g.Wait(); err != nil {
		return out, err
	}

	if err != nil {
		return nil, err
	}

	for i, resp := range out {
		if v, ok := batterMap[resp.BatteryId]; ok {
			out[i].BatteryType = v.Type
			out[i].BatteryCapacity = v.Capacity
		}

		resp.Photo = resp.Image
		if resp.Photo == "" {
			if len(resp.ImagePath) > 0 {
				out[i].Photo = resp.ImagePath[0]
			}
		}

		// 获取用户自定义的车辆名称
		//if v, ok := bikeMap[resp.ID]; ok {
		//	out[i].Name = v.EbikeName
		//}
		customData := UserEbike.GetBikeCustomData(userId, out[i].ID)
		out[i].Name = customData.Name

		out[i].Photo = EbikeType.GetBikeImage(resp.DeviceTypeId, resp.Color)
		out[i].IsShowCouch = a.IsShowCouch(resp.DeviceTypeName)

		// 构建车辆配置信息
		for _, v := range settingsMap {
			if v.EbikeId == resp.ID {
				out[i].AdditionalProps = append(out[i].AdditionalProps, &model.Prop{
					PropId:  1,
					PropVal: v.EbikeSet.PowerValue,
				})
			}
		}
	}

	sort.Slice(out, func(i, j int) bool {
		return out[i].CreatedAt > out[j].CreatedAt
	})

	return out, err
}

// IsValid 检查车辆是否有效
func (a *ebike) IsValid(bikeId int64) bool {
	// 查询车辆信息
	if bikeInfo, err := a.iEbike.Find(context.Background(), bikeId); err != nil || bikeInfo == nil {
		return false
	}
	return true
}

// Exec 车辆开启关闭
func (a *ebike) Exec(ctx context.Context, in *model.EbikeAppExecRequest) error {
	/*	var (
			err    error
			userID int64
			info   *model.UserEbikeAndEbikeInfo
			bike   *model.UserEbikeAndEbikeResponse
			onoff  dto.PowerOperate
		)

		// 查询车辆关联表信息

		userID, err = auth.ContextUserID(ctx)
		if err != nil {
			return err
		}

		info = &model.UserEbikeAndEbikeInfo{
			UserID:  userID,
			EbikeID: in.EbikeID,
		}

		bike, err = a.iUserEbike.FindBikeAndUserBike(ctx, info)
		if err != nil {
			return err
		}
		if *in.OnOff == int(model.ExecOFF) {
			onoff = dto.PowerOperate_Off
		} else {
			onoff = dto.PowerOperate_On
		}

		// grpc 请求
		_, err = grpc.Cmd.Power(ctx, &dto.PowerRequest{
			Sn:      bike.SnCode,
			Operate: onoff,
		})
		if err != nil {
			log.Error(err)
			return errors.EbikeControlFailed.Error()
		}
	*/
	// 返回信息
	return nil
}

func (a *ebike) AesInfo(ctx context.Context, sn string) (*model.EbikeInfo, error) {
	var (
		err  error
		info *model.EbikeInfo
		ety  *model.EbikeInfo
	)
	ety, err = CacheBike.GetBikeInfoBySn(sn)
	if err != nil {
		return nil, err
	}
	info = &model.EbikeInfo{
		ID:         ety.ID,
		TypeID:     ety.TypeID,
		Name:       ety.Name,
		Status:     ety.Status,
		FrameCode:  ety.FrameCode,
		EngineCode: ety.EngineCode,
		Color:      ety.Color,
		IsBind:     ety.IsBind,
		Stock:      ety.Stock,
		FirmwareID: 0,
		AESKey:     ety.AESKey,
		IV:         ety.IV,
		StoreID:    ety.StoreID,
		CreatedAt:  ety.CreatedAt,
		UpdatedAt:  ety.UpdatedAt,
		SNCode:     ety.SNCode,
	}

	return info, err
}

func (a *ebike) Info(ctx context.Context, in *model.EbikeBaseRequest) (*model.EbikeInfoResponse, error) {
	var (
		err        error
		ety        *entity.Ebike
		out        *model.EbikeInfoResponse
		typeEty    *entity.EbikeType
		controlEty *entity.Control
	)

	ety, err = a.iEbike.Find(ctx, in.ID)

	if err != nil && errors.Is(gorm.ErrRecordNotFound, err) {
		return nil, errors.EbikeNotExist.Error()
	}
	if err != nil {
		log.Error(err)
		return nil, err
	}
	// 查询 中控信息
	controlEty, err = a.iControl.Find(ctx, &model.ControlInfoRequest{
		Id: ety.ControlId,
	})
	if err != nil {
		log.Error(err)
	}
	//查询车型信息
	typeEty, err = a.iEbikeType.Find(ety.TypeID)
	if err != nil {
		return nil, err
	}

	out = &model.EbikeInfoResponse{
		ID:         ety.ID,
		TypeID:     ety.TypeID,
		TypeName:   typeEty.Name,
		Name:       ety.Name,
		Status:     ety.Status,
		FrameCode:  ety.FrameCode,
		EngineCode: ety.EngineCode,
		Color:      ety.Color,
		IsBind:     ety.IsBind,
		Stock:      ety.Stock,
		FirmwareID: 0,
		StoreID:    ety.StoreID,
		CreatedAt:  ety.CreatedAt,
		UpdatedAt:  ety.UpdatedAt,
		BindUsers:  ety.BindUsers,
		SNCode:     ety.SNCode,
		Mac:        controlEty.Mac,
		Imei:       controlEty.Imei,
		Iccid:      controlEty.Iccid,
		Imsi:       controlEty.Imsi,
	}

	return out, err
}

func (a *ebike) FindBySn(ctx context.Context, sn string) (*model.AppEbikeFindBySnResponse, error) {
	// 查询车辆信息
	bikeInfo, err := CacheBike.GetBikeInfoBySn(sn)
	if err != nil {

	}
	if err != nil {
		return nil, errors.EbikeQueryFailed.Error()
	}

	// 查询车辆关联表信息
	bikeData, err := a.iEbike.FindBySn(ctx, sn)
	if err != nil {
		return nil, errors.EbikeQueryFailed.Error()
	}

	// 查询车辆自定义信息
	userId, _ := auth.ContextUserID(ctx)
	data := UserEbike.GetBikeCustomData(userId, bikeInfo.ID)

	return &model.AppEbikeFindBySnResponse{
		Photo:     data.Image,
		FrameCode: bikeData.FrameCode,
		Name:      data.Name,
		IsBind:    bikeData.IsBind,
	}, err
}

func (a *ebike) Lock(ctx context.Context, in *model.EbikeAppLockRequest) error {
	var (
		err        error
		updateInfo = &model.EbikeUpdateRequest{}
	)
	updateInfo.ID = in.EbikeID
	updateInfo.Status = in.Status

	err = a.iEbike.ExecTx(ctx, func(ctx context.Context) error {

		//todo 调用rpc 车辆锁定

		err = a.Update(ctx, updateInfo)
		if err != nil {
			log.Error(err)
			return errors.EbikeControlFailed.Error()
		}

		return nil
	})

	return err
}

// Distribute 车辆分发
func (a *ebike) Distribute(ctx context.Context, in *model.EbikeDistributeRequest) error {
	var (
		err      error
		ety      *entity.Ebike
		storeEty *entity.Store
	)

	//  判断车辆状态
	ety, err = a.iEbike.Find(ctx, in.EbikeId)

	if err != nil && errors.Is(gorm.ErrRecordNotFound, err) {
		return errors.EbikeQueryFailed.Error()
	}
	if err != nil {
		log.Error(err)
		return err
	}

	if ety.Stock != 0 {
		return errors.New("出库状态异常")
	}

	//  查询门店状态
	storeEty, err = a.iStore.Find(ctx, in.StoreId)
	if err != nil && errors.Is(gorm.ErrRecordNotFound, err) {
		return errors.New("门店不存在")
	}
	if err != nil {
		log.Error(err)
		return err
	}
	if storeEty.Status == int(model.StoreOffLine) {
		return errors.New("门店已下线")
	}

	storeOut := int(model.StockFactoryOut)

	// 车辆分发
	now := time.Now().Unix()
	err = a.Update(ctx, &model.EbikeUpdateRequest{
		ID:             in.EbikeId,
		Stock:          &storeOut,
		StoreID:        &in.StoreId,
		DistributeTime: &now,
	})
	if err != nil {
		log.Error(err)
		return err
	}

	return nil
}

// Change 车辆变动
func (a *ebike) Change(ctx context.Context, in *model.EbikeChangeRequired) error {
	var (
		err error
		ety *entity.UserEbike
	)
	if in.IsClear == nil {
		noDelete := 0
		in.IsClear = &noDelete
	}

	//查询车辆信息
	ety, err = a.iUserEbike.FindByParameter(ctx, &model.UserEbikeRequest{EbikeID: &in.EbikeId, UserID: &in.UserId})
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		return errors.EbikeNotBound.Error()
	}

	if err != nil {
		log.Error(err)
		return err
	}

	// 解绑
	err = a.iEbike.ExecTx(ctx, func(ctx context.Context) error {
		defer utils.ExceptionCatch()
		// 发送车辆解绑车主事件
		data := &event.UnBindBike{
			BikeId: ety.ID,
			UserId: ety.UserID,
		}

		event.Emit(&event.Data{
			Type: event.Event_UnBind_Bike,
			Data: data,
		})

		// 判断是否要删除其他数据
		if in.IsClear != nil && *in.IsClear == 1 {
			// 清除车辆数据
			event.Emit(&event.Data{
				Type: event.Event_Clear_Data,
				Data: &event.ClearBikeData{
					BikeId: ety.ID,
					UserId: ety.UserID,
				},
			})
		}

		// 车辆解绑
		userId, _ := auth.ContextUserID(ctx)
		isManager := UserEbike.IsManager(in.UserId, in.EbikeId)
		err = a.iEbike.UnBind(ctx, in.UserId, in.EbikeId, isManager)
		if err != nil {
			log.Error(err)
			TableLog.AddOperatorLog(userId, EnDel, "user_bike", fmt.Sprintf("%v_%v_%v_%v", "Change", utils.ToJsonString(data), isManager, err.Error()))
			return err
		}

		// 添加日志
		TableLog.AddOperatorLog(userId, EnDel, "user_bike", fmt.Sprintf("%v_%v_%v", "Change", utils.ToJsonString(data), isManager))
		return nil
	})

	return err
}

// BatchCreate 批量添加车辆
func (a *ebike) BatchCreate(c context.Context, filePath string, in *model.BatchCreateReq) (err error, failedList []string) {
	defer utils.ExceptionCatch()
	var (
		file *excelize.File
	)

	// 电池类型校验
	if !BatteryType.IsExistBatteryType(in.BatteryType) {
		return errors.BatteryTypeNotExist.Error(), nil
	}

	// 判断车型是否存在
	_, err = EbikeType.BikeTypeInfo(in.TypeID)
	if err != nil {
		return errors.EbikeModelNotExist.Error(), nil
	}

	// 读取表格内容
	if file, err = excelize.OpenFile(filePath); err != nil {
		trace_log.ErrorLogger.Error("ebike upload open file err:", err.Error())
		return errors.FileParsingFailed.Warp(err, "文件解析失败"), nil
	}

	defer file.Close()

	sheets := file.GetSheetMap()

	// 获取工作表中指定单元格的值
	rows, err := file.GetRows(sheets[1])
	if err != nil {
		return errors.FileParsingFailed.Warp(err, "excel 格式解析错误"), nil
	}

	if len(rows) == 0 {
		return fmt.Errorf("没有数据"), nil
	}

	failedList = make([]string, 0)
	for index := 0; index < len(rows); index++ {
		if index == 0 {
			continue
		}

		row := rows[index]
		if row[0] == "" {
			failedList = append(failedList, row[0])
			continue
		}

		snCode := row[0]
		frameCode := ""
		if len(row) >= 2 {
			frameCode = row[1]
		}

		engineCode := ""
		if len(row) >= 3 {
			engineCode = row[2]
		}

		if snCode == "" || len([]byte(snCode)) != 16 {
			failedList = append(failedList, snCode)
			continue
		}

		// 创建车辆
		_err := a.Create(c, &model.EbikeCreateRequest{
			TypeID:      in.TypeID,
			Photo:       in.Photo,
			FrameCode:   frameCode,
			EngineCode:  engineCode,
			SNCode:      snCode,
			Color:       in.Color,
			BatteryType: in.BatteryType,
		})
		if _err != nil {
			trace_log.ErrorLogger.Error("batch create ebike err:", _err.Error(), "snCode:", snCode)
			failedList = append(failedList, snCode)
		}

		time.Sleep(time.Millisecond * 20)
	}

	return nil, failedList
}

// Upload 文件上传
func (a *ebike) Upload(c context.Context, dst string) error {
	var (
		err         error
		file        *excelize.File
		ebikeList   = make([]entity.Ebike, 0)
		controlList = make([]entity.Control, 0)
		batteryList = make([]entity.Battery, 0)
	)

	defer func() {
		if err := file.Close(); err != nil {
			log.Error(err)
		}
	}()
	// 读取表格内容
	if file, err = excelize.OpenFile(dst); err != nil {
		log.Errorf("ebike upload open file err[%s]", err.Error())
		return errors.FileParsingFailed.Warp(err, "文件解析失败")
	}

	sheets := file.GetSheetMap()

	// 获取工作表中指定单元格的值
	rows, err := file.GetRows(sheets[1])
	if err != nil {
		return errors.FileParsingFailed.Warp(err, "excel 格式解析错误")
	}
	for index, row := range rows {
		if index == 0 {
			continue
		}
		// 车辆
		ebikeEty := entity.Ebike{
			BindUsers: make([]string, 0),
			CreatedAt: time.Now().Unix(),
			UpdatedAt: time.Now().Unix(),
		}

		// 中控
		controlEty := entity.Control{
			CreatedAt: time.Now().Unix(),
			UpdatedAt: time.Now().Unix(),
		}

		// 电池
		batteryEty := entity.Battery{
			CreatedAt: time.Now().Unix(),
			UpdatedAt: time.Now().Unix(),
		}
		for i, value := range row {
			if i == 0 { // sn
				// 判断是否16位
				if len(value) != 16 {
					return errors.SNCodeIncorrectLength.Error()
				}
				ebikeEty.SNCode = value
				controlEty.SnCode = value
			}
			if i == 1 { // 车型ID
				if len(value) == 0 {
					return errors.ParameterErr.Error()
				}
				// 转换成int64
				typeId, err := strconv.ParseInt(value, 10, 64)
				if err != nil {
					return err
				}
				ebikeEty.TypeID = typeId
			}
			if i == 2 { // 车架号 16位
				// 判断是否16位
				if len(value) != 16 {
					return errors.FrameCodeIncorrectLength.Error()
				}
				ebikeEty.FrameCode = value
				controlEty.FrameCode = value
			}
			if i == 3 { // 车辆名称
				// 为空的时候自己生成一个
				if len(value) == 0 {
					// 生成一个名称
					ebikeEty.Name = utils.RandString(10)
				} else {
					ebikeEty.Name = value
				}
			}
			if i == 4 { //电机号
				ebikeEty.EngineCode = value
			}
			if i == 5 { // aeskey
				ebikeEty.AESKey = value
			}
			if i == 6 { //iv 向量
				ebikeEty.IV = value
			}
			if i == 7 { // 颜色
				ebikeEty.Color = value
			}
			if i == 8 { // 中控mac地址
				//判断为空
				if len(value) == 0 {
					log.Error("mac地址为空")
					return errors.ParameterErr.Error()
				}
				controlEty.Mac = value
			}
			if i == 9 { // imei
				controlEty.Imei = value
			}
			if i == 10 { // iccid
				controlEty.Iccid = value
			}
			if i == 11 { //imsi
				controlEty.Imsi = value
			}
			if i == 12 { // 中控版本号
				//中控版本号
				controlEty.FirmwareVersion = value
			}
			if i == 13 { // 中控固件id
				firmwareID, err := strconv.ParseInt(value, 10, 64)
				if err != nil {
					log.Error(err)
					return err
				}
				controlEty.FirmwareId = firmwareID
			}
		}
		ebikeList = append(ebikeList, ebikeEty)
		controlList = append(controlList, controlEty)
		batteryList = append(batteryList, batteryEty)

	}
	if len(ebikeList) == 0 { // 没有值直接返回成功
		return nil
	}
	// 批量存储

	if err = a.iEbike.Upload(c, ebikeList, controlList, batteryList); err != nil {
		log.Errorf("ebike upload  err[%s]", err.Error())
		return errors.FileUploadErr.Error()
	}
	return err
}

// OperationInfo 运行信息
func (a *ebike) OperationInfo(ctx context.Context, in *model.OperationInfoReq) (rsp *model.OperationInfoRsp, err error) {
	// 查询设备影子
	info, _ := CacheBike.GetBikeInfoById(in.EbikeId)
	if info.ID == 0 {
		return nil, errors.EbikeNotExist.Error()
	}

	// 电池信息
	batterMap := make(map[int64]*model.BatteryData)
	_, batteryList, _ := postgres.Battery.BatteryInfoList(ctx, []int64{info.BatteryId})
	for i := 0; i < len(batteryList); i++ {
		batterMap[batteryList[i].Id] = batteryList[i]
	}

	// 查询设备影子
	shadowRsp, err := grpc.SCmd.GetShadowAttributes(ctx, &dto.GetShadowAttributesRequest{
		DeviceName: info.SNCode,
	})

	if err != nil {
		return
	}

	fmt.Println("------------------[OperationInfo data:", utils.ToJsonString(shadowRsp), "] ----------------")

	// 解析影子
	var attribute model.ShadowAttribute
	if shadowRsp.Attribute != "" {
		err = json.Unmarshal([]byte(shadowRsp.Attribute), &attribute)
		if err != nil {
			return
		}
	}

	batteryCapacity := "72ah"
	if v, ok := batterMap[info.BatteryId]; ok {
		batteryCapacity = v.Capacity
	}

	rsp = &model.OperationInfoRsp{
		EbikeId:            in.EbikeId,
		BatteryCapacity:    batteryCapacity,
		BatteryLevel:       int(utils.StrToInt64(attribute.Soc) / 10),
		BatteryHealth:      int(utils.StrToInt64(attribute.Soh)),
		ChargingTime:       int(utils.StrToInt64(attribute.RemainTime)),
		Temperature:        int((utils.StrToInt64(attribute.Temperature) - 400) / 10),
		BatteryVoltage:     int(utils.StrToInt64(attribute.Voltage)),
		ChargeDischarge:    int(utils.StrToInt64(attribute.Loop)),
		Endurance:          30,
		GPS:                utils.StrToInt64(attribute.SignalGps) > 0,
		Bluetooth:          false,
		Net:                utils.StrToInt64(attribute.Signal4g) > 0,
		ConsumerPowerOfDay: 0,
		FirmwareVersion:    attribute.FirmwareVersion,
	}

	var errG errgroup.Group

	// 震动次数
	errG.Go(func() error {
		alarmTypeInfo, _ := CacheAlarmType.GetAlarmType("shock")
		if alarmTypeInfo != nil && alarmTypeInfo.Id > 0 {
			rsp.VibrationTimes = int(Alarm.AlarmTimes(context.Background(), in.EbikeId, alarmTypeInfo.Id))
		}
		return nil
	})

	// 倾倒次数
	errG.Go(func() error {
		rsp.AlarmTimes = int(Alarm.AlarmTimes(context.Background(), in.EbikeId, 0))
		return nil
	})

	// 故障次数
	errG.Go(func() error {
		rsp.FaultTimes = int(Fault.FaultTimes(context.Background(), in.EbikeId))
		return nil
	})

	errG.Wait()
	return
}

// AuthTransfer 授权转移
func (a *ebike) AuthTransfer(ctx context.Context, in *model.AuthTransferReq) error {
	// 获取用户ID
	userID, _ := auth.ContextUserID(ctx)
	if userID == 0 {
		return fmt.Errorf("token get user id failed")
	}

	// 查询车辆是否拥有
	if !UserEbike.IsUserBindBike(userID, in.EbikeId) {
		return fmt.Errorf("user not bind ebike")
	}

	// 创建转移记录
	id, err := a.iAuthTransfer.Create(ctx, &entity.TransferRecode{
		UserId:     userID,
		EbikeId:    in.EbikeId,
		BindPhones: in.TargetPhones,
	})
	if err != nil || id == 0 {
		return fmt.Errorf("create transfer recode failed")
	}

	// 解绑原用户车辆
	if err = a.UnBind(ctx, &model.EbikeBaseRequest{
		ID: in.EbikeId,
	}); err != nil {
		return err
	}

	// 修改预绑定电话列表
	var bindUsers pq.StringArray
	for i := 0; i < len(in.TargetPhones); i++ {
		bindUsers = append(bindUsers, in.TargetPhones[i])
	}

	// 更新车辆绑定用户电话号码
	err = a.Update(ctx, &model.EbikeUpdateRequest{
		ID:        in.EbikeId,
		BindUsers: &bindUsers,
	})
	if err != nil {
		return err
	}

	// 发送解绑事件
	err = a.iAuthTransfer.Update(ctx, id, map[string]interface{}{
		"status": 1,
	})
	return err
}

// IsShowCouch 是否显示坐垫
func (a *ebike) IsShowCouch(bikeTypeName string) bool {
	return bikeTypeName != "SRT5"
}
